package com.shop.cereshop.app.controller.nearbyUser;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.shop.cereshop.app.service.buyer.CereBuyerUserService;
import com.shop.cereshop.app.service.nearby.BuyerNearbyImageService;
import com.shop.cereshop.app.service.nearbyUser.NearbyUserService;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.domain.buyer.CereBuyerUser;
import com.shop.cereshop.commons.domain.buyer.FollowUserVo;
import com.shop.cereshop.commons.domain.buyer.NearByUserInfoVo;
import com.shop.cereshop.commons.domain.common.Page;
import com.shop.cereshop.commons.domain.nearby.BuyerNearbyImage;
import com.shop.cereshop.commons.enums.RedisEnum;
import com.shop.cereshop.commons.result.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.Metrics;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("nearbyUser")
@Api(value = "附近用户模块", tags = "附近用户模块")
public class NearbyUserController {

    @Resource
    private CereBuyerUserService buyerUserService;

    @Resource
    private NearbyUserService nearbyService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private BuyerNearbyImageService buyerNearbyImageService;

    @PostMapping("/update")
    @ApiOperation(value = "更新用户地理位置")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "lng", value = "经度", required = true, dataType = "Double", paramType = "query"),
            @ApiImplicitParam(name = "lat", value = "纬度", required = true, dataType = "Double", paramType = "query")
    })
    public Result updateLocation(HttpServletRequest request, @RequestParam Double lng, @RequestParam Double lat) {
        CereBuyerUser user = (CereBuyerUser) request.getAttribute("user");
        if (BeanUtil.isEmpty(user)) {
            return new Result(CoReturnFormat.USER_NOT_LOGIN);
        }
//        nearbyService.updateUserLocation(user.getBuyerUserId(), lng, lat);
        //todo 临时写死 。保证大家在同一位置
        nearbyService.updateUserLocation(user.getBuyerUserId(), 117.356821, 31.865616);
        return new Result(CoReturnFormat.SUCCESS);
    }

    @PostMapping("/searchNearbyPaged")
    @ApiOperation(value = "搜索附近用户（分页+多条件）")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "distance", value = "搜索距离(公里)", required = false, dataType = "Double", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "页码(从1开始)", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "每页大小", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "sex", value = "性别(男/女)", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "ageMin", value = "最小年龄", required = false, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "ageMax", value = "最大年龄", required = false, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "member", value = "是否会员(true/false)", required = false, dataType = "Boolean", paramType = "query"),
            @ApiImplicitParam(name = "onlineOnly", value = "仅在线(true/false)", required = false, dataType = "Boolean", paramType = "query")
    })
    public Result searchNearbyPaged(
            HttpServletRequest request,
            @RequestParam Integer page,
            @RequestParam Integer pageSize,
            @RequestParam(required = false, defaultValue = "5") Double distance,
            @RequestParam(required = false) String sex,
            @RequestParam(required = false) Integer ageMin,
            @RequestParam(required = false) Integer ageMax,
            @RequestParam(required = false) Boolean member,
            @RequestParam(required = false) Boolean onlineOnly) {
        CereBuyerUser user = (CereBuyerUser) request.getAttribute("user");
        if (BeanUtil.isEmpty(user)) {
            return Result.failed(CoReturnFormat.USER_NOT_LOGIN);
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> nearbyByUserList = nearbyService.findNearbyByUserId(user.getBuyerUserId(), distance, Metrics.KILOMETERS);
        if (CollUtil.isEmpty(nearbyByUserList)) {
            return Result.success(new Page<>(null, 0));
        }
        // 提取ID，保留顺序（按距离升序）
        List<String> allIds = nearbyByUserList.stream()
                .map(r -> r.getContent().getName())
                .filter(id -> !id.equals(String.valueOf(user.getBuyerUserId())))
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(allIds)) {
            return Result.success(new Page<>(null, 0));
        }

        // 查询用户基础信息
        List<CereBuyerUser> cereBuyerUsers = buyerUserService.selectByUserIds(allIds);

        List<BuyerNearbyImage> buyerNearbyImageList = buyerNearbyImageService.listByUserIds(allIds);
        Map<Long, List<BuyerNearbyImage>> idToImages = buyerNearbyImageList.stream().collect(Collectors.groupingBy(BuyerNearbyImage::getBuyerUserId));

        Map<Long, CereBuyerUser> idToUser = cereBuyerUsers.stream().collect(Collectors.toMap(CereBuyerUser::getBuyerUserId, u -> u, (a, b) -> a));

        // 在线阈值：最近5分钟更新过位置视为在线
        long now = System.currentTimeMillis();
        long onlineThresholdMs = 5 * 60 * 1000L;
        ZSetOperations<String, String> zSetOps = redisTemplate.opsForZSet();

        List<NearByUserInfoVo> filtered = new ArrayList<>();
        for (GeoResult<RedisGeoCommands.GeoLocation<String>> r : nearbyByUserList) {
            String idStr = r.getContent().getName();
            if (idStr.equals(String.valueOf(user.getBuyerUserId()))) {
                continue;
            }
            Long uid = Long.valueOf(idStr);
            CereBuyerUser info = idToUser.get(uid);
            if (info == null) {
                continue;
            }
            // 性别过滤（规范化比较；当传入性别时，未设置性别的用户将被排除）
            if (sex != null && !sex.trim().isEmpty()) {
                if (StrUtil.isEmpty(info.getSex()) || !StrUtil.equals(sex, info.getSex())) {
                    continue;
                }
            }
            // 年龄过滤
            Integer userAge = computeAgeSafe(info.getBirthday());
            if (ageMin != null && (userAge == null || userAge < ageMin)) {
                continue;
            }
            if (ageMax != null && (userAge == null || userAge > ageMax)) {
                continue;
            }
            // 会员过滤（有会员等级认为是会员）
            if (member != null) {
                if (info.getMemberLevelId() == null || info.getMemberLevelId() <= 1) {
                    continue;
                }
            }
            // 在线过滤（基于最后更新时间戳）
            NearByUserInfoVo vo = new NearByUserInfoVo();
            Double score = zSetOps.score(RedisEnum.USER_LOCATION_TS_KEY.getKey(), idStr);
            if (score == null || (now - score.longValue()) > onlineThresholdMs) {
                vo.setOnline(false);
                if (onlineOnly != null && onlineOnly) {
                    continue;
                }
            }
            vo.setUserId(info.getBuyerUserId());
            vo.setName(info.getName());
            vo.setHeadImage(info.getHeadImage());
            vo.setOther(r);
            vo.setSex(info.getSex());
            vo.setAge(userAge);
            vo.setMemberLevel(info.getMemberLevelId());
            vo.setBuyerNearbyImageList(idToImages.get(info.getBuyerUserId()));
            filtered.add(vo);
        }

        // 分页
        int fromIndex = Math.max(0, (page - 1) * pageSize);
        int toIndex = Math.min(filtered.size(), fromIndex + pageSize);
        if (fromIndex >= filtered.size()) {
            return Result.success(new Page<>(new ArrayList<>(), filtered.size()));
        }

        List<NearByUserInfoVo> pageList = filtered.subList(fromIndex, toIndex);
        return Result.success(new Page<>(pageList, filtered.size()));
    }

    private Integer computeAgeSafe(String birthday) {
        try {
            if (birthday == null || birthday.trim().isEmpty()) {
                return null;
            }
            java.time.LocalDate birth;
            try {
                birth = java.time.LocalDate.parse(birthday.substring(0, Math.min(birthday.length(), 10)));
            } catch (Exception e) {
                // 尝试常见格式
                java.time.format.DateTimeFormatter fmt = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
                birth = java.time.LocalDate.parse(birthday.substring(0, Math.min(birthday.length(), 10)), fmt);
            }
            java.time.Period p = java.time.Period.between(birth, java.time.LocalDate.now());
            return Math.max(0, p.getYears());
        } catch (Exception e) {
            return null;
        }
    }

    @PostMapping("/search")
    @ApiOperation(value = "搜索附近用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "lng", value = "经度", required = true, dataType = "Double", paramType = "query"),
            @ApiImplicitParam(name = "lat", value = "纬度", required = true, dataType = "Double", paramType = "query"),
            @ApiImplicitParam(name = "distance", value = "搜索距离", required = false, dataType = "Double", paramType = "query")
    })
    public Result searchNearby(
            @RequestParam Double lng,
            @RequestParam Double lat,
            @RequestParam(defaultValue = "5") Double distance) {
        // 默认搜索 5 公里内的人
        return new Result(nearbyService.findNearby(lng, lat, distance, Metrics.KILOMETERS), CoReturnFormat.SUCCESS);
    }

    @PostMapping("/searchNearbyUserId")
    @ApiOperation(value = "搜索附近用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "distance", value = "搜索距离", required = false, dataType = "Double", paramType = "query")
    })
    public Result searchNearbyUserId(
            HttpServletRequest request,
            @RequestParam(defaultValue = "5") Double distance) {
        // 默认搜索 5 公里内的人
        //获取当前登录账户
        CereBuyerUser user = (CereBuyerUser) request.getAttribute("user");
        if (BeanUtil.isEmpty(user)) {
            return new Result(CoReturnFormat.USER_NOT_LOGIN);
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> nearbyByUserList = nearbyService.findNearbyByUserId(user.getBuyerUserId(), distance, Metrics.KILOMETERS);
        List<FollowUserVo> followUserList = new ArrayList<>();
        if (CollUtil.isNotEmpty(nearbyByUserList)) {
            //提取 nearbyByUserList中的name为一个集合
            List<String> userIdList = nearbyByUserList.stream().map(GeoResult::getContent).map(RedisGeoCommands.GeoLocation::getName).collect(Collectors.toList());
            List<CereBuyerUser> cereBuyerUsers = buyerUserService.selectByBuyerUserIds(userIdList, null);
            Map<Long, List<CereBuyerUser>> userInfoMap = cereBuyerUsers.stream().collect(Collectors.groupingBy(CereBuyerUser::getBuyerUserId));
            for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult : nearbyByUserList) {
                String userId = geoLocationGeoResult.getContent().getName();
                //判断查询出来的用户是否是自己 如果是自己不进行返回
                if (userId.equals(user.getBuyerUserId().toString())) {
                    continue;
                }
                CereBuyerUser cereBuyerUser = userInfoMap.get(Long.valueOf(userId)).get(0);
                FollowUserVo followUserVo = new FollowUserVo();
                followUserVo.setUserId(cereBuyerUser.getBuyerUserId());
                followUserVo.setName(cereBuyerUser.getName());
                followUserVo.setHeadImage(cereBuyerUser.getHeadImage());
                followUserVo.setOther(geoLocationGeoResult);
                followUserList.add(followUserVo);
            }
            return new Result(followUserList, CoReturnFormat.SUCCESS);
        }
        return new Result(CoReturnFormat.SUCCESS);
    }


}
